home *** CD-ROM | disk | FTP | other *** search
/ Delphi Developer's Kit 1996 / Delphi Developer's Kit 1996.iso / power / wfc007.000 / src / sockets.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1995-12-22  |  22.7 KB  |  904 lines

  1. #include <wfc.h>
  2. #pragma hdrstop
  3.  
  4. /*
  5. ** Author: Samuel R. Blackburn
  6. ** CI$: 76300,326
  7. ** Internet: sammy@sed.csc.com
  8. **
  9. ** You can use it any way you like.
  10. */
  11.  
  12. #if defined( _DEBUG )
  13. #undef THIS_FILE
  14. static char BASED_CODE THIS_FILE[] = __FILE__;
  15. #endif
  16.  
  17. CSimpleSocket::CSimpleSocket()
  18. {
  19.    m_Initialize();
  20. }
  21.  
  22. CSimpleSocket::~CSimpleSocket()
  23. {
  24.    TRACE( "Destroying a CSimpleSocket object\n" );
  25.    Close();
  26. }
  27.  
  28. void CSimpleSocket::Close( void )
  29. {
  30.    ASSERT_VALID( this );
  31.  
  32.    if ( m_SocketID != INVALID_SOCKET )
  33.    {
  34.       ::closesocket( m_SocketID );
  35.       m_SocketID = INVALID_SOCKET;
  36.       m_hFile    = CFile::hFileNull;
  37.    }
  38.  
  39.    Name.Empty();
  40.    Address.Empty();
  41.    m_ClearAliasList();
  42. }
  43.  
  44. void CSimpleSocket::Dump( CDumpContext &dump_context ) const
  45. {
  46.    CObject::Dump( dump_context );
  47.  
  48.    dump_context << "ip_address is \"" << Address  << "\"";
  49.    dump_context << "name is       \"" << Name       << "\"";
  50.    dump_context << "port name is  \"" << m_PortName << "\"";
  51.    dump_context << "port # is      "  << ::ntohs( m_PortNumberInNetworkByteOrder );
  52. }
  53.  
  54. void CSimpleSocket::GetAddress( CString& _address ) const
  55. {
  56.    ASSERT_VALID( this );
  57.  
  58.    _address = Address;
  59. }
  60.  
  61. SOCKET CSimpleSocket::GetID( void ) const
  62. {
  63.    ASSERT_VALID( this );
  64.  
  65.    return( m_SocketID );
  66. }
  67.  
  68. void CSimpleSocket::GetName( CString& _host_name ) const
  69. {
  70.    ASSERT_VALID( this );
  71.  
  72.    _host_name = Name;
  73. }
  74.  
  75. void CSimpleSocket::GetPort( short& _port_number ) const
  76. {
  77.    ASSERT_VALID( this );
  78.  
  79.    _port_number = ::ntohs( m_PortNumberInNetworkByteOrder );
  80. }
  81.  
  82. void CSimpleSocket::GetPort( CString& _port_name ) const
  83. {
  84.    ASSERT_VALID( this );
  85.  
  86.    _port_name = m_PortName;
  87. }
  88.  
  89. BOOL CSimpleSocket::IsDataWaiting( void )
  90. {
  91.    ASSERT_VALID( this );
  92.  
  93.    if ( m_SocketID == INVALID_SOCKET )
  94.    {
  95.       return( FALSE );
  96.    }
  97.  
  98.    int bytes_for_this_socket = 0;
  99.    int socket_status         = 0;
  100.  
  101.    FD_SET socket_in;
  102.  
  103.    TIMEVAL time_out;
  104.  
  105.    /*
  106.    ** Initialize the data structures
  107.    */
  108.  
  109.    FD_ZERO( (LPFD_SET) &socket_in );
  110.  
  111.    time_out.tv_sec  = 0;
  112.    time_out.tv_usec = 0;
  113.  
  114.    /*
  115.    ** Set socket_in to specify that we are looking for data on socket port_id
  116.    */
  117.  
  118.    FD_SET( m_SocketID, (LPFD_SET) &socket_in );
  119.  
  120.    /*
  121.    ** See if data is waiting
  122.    */
  123.  
  124.    socket_status = ::select( 0, &socket_in, NULL, NULL, &time_out );
  125.  
  126.    if ( socket_status == SOCKET_ERROR )
  127.    {
  128.       TRACE2( "CSimpleSocket::IsDataWaiting(), Can't select() at line %d of %s\n", __LINE__, __FILE__ );
  129.  
  130.       m_ErrorCode = ::WSAGetLastError();
  131.       return( FALSE );
  132.    }
  133.  
  134.    if ( socket_status == 0 )
  135.    {
  136.       /*
  137.       ** No Data is waiting on any socket in the OS
  138.       */
  139.  
  140.       return( FALSE );
  141.    }
  142.  
  143.    /*
  144.    ** Welp, data is waiting for *A* socket. It may not be *our* socket. A socket in the
  145.    ** operating system has data waiting in it. Let's see if it happens to be *our* socket.
  146.    */
  147.  
  148.    bytes_for_this_socket = ::FD_ISSET( m_SocketID, &socket_in );
  149.    
  150.    if ( bytes_for_this_socket == 0 )
  151.    {
  152.       /*
  153.       ** There is data for a socket somewhere in the system but not for our socket
  154.       */
  155.  
  156.       return( FALSE );
  157.    }
  158.  
  159.    return( TRUE );
  160. }
  161.  
  162. void CSimpleSocket::m_ClearAliasList( void )
  163. {
  164.    ASSERT_VALID( this );
  165.  
  166.    POSITION pos = AliasList.GetHeadPosition();
  167.  
  168.    CString *string_p = NULL;
  169.  
  170.    while( pos != NULL )
  171.    {
  172.       string_p = (CString *) AliasList.GetNext( pos );
  173.  
  174.       delete string_p;
  175.    }
  176.  
  177.    AliasList.RemoveAll();
  178. }
  179.  
  180. void CSimpleSocket::m_Initialize( void )
  181. {
  182.    ASSERT_VALID( this ) ;
  183.  
  184.    TRACE( "CsimpleSocket::m_Initialize()\n" );
  185.  
  186.    /*
  187.    ** Make sure everything is empty
  188.    */
  189.  
  190.    m_PortNumberInNetworkByteOrder = 0;
  191.    m_SocketID                     = INVALID_SOCKET;
  192.    m_hFile                        = CFile::hFileNull;
  193.  
  194.    Address.Empty();
  195.    Name.Empty();
  196.    m_PortName.Empty();
  197.  
  198.    m_ClearAliasList();
  199. }
  200.  
  201. UINT CSimpleSocket::Read( VOID *buffer, const int size_of_buffer )
  202. {
  203.    ASSERT_VALID( this );
  204.    ASSERT( buffer != NULL );
  205.    ASSERT( size_of_buffer > 0 );
  206.  
  207.    if ( buffer == NULL )
  208.    {
  209.       m_ErrorCode = ERROR_INVALID_PARAMETER;
  210.       return( 0 );
  211.    }
  212.  
  213.    if ( m_SocketID != INVALID_SOCKET )
  214.    {
  215.       int number_of_bytes_read = 0;
  216.  
  217.       ::ZeroMemory( buffer, size_of_buffer );
  218.    
  219.       number_of_bytes_read = ::recv( m_SocketID, (char *) buffer, size_of_buffer, 0 );
  220.    
  221.       if ( number_of_bytes_read == SOCKET_ERROR )
  222.       {
  223.          TRACE( "CSimpleSocket::Read(), Error in recv() at line %d of %s\n", __LINE__, __FILE__ );
  224.  
  225.          m_ErrorCode = ::WSAGetLastError();
  226.          return( 0 );
  227.       }
  228.       
  229.       return( number_of_bytes_read );   
  230.    }
  231.    else
  232.    {
  233.       return( 0 );
  234.    }
  235. }
  236.  
  237. void CSimpleSocket::Read( CString& line_to_read )
  238. {
  239.    ASSERT_VALID( this );
  240.  
  241.    if ( m_SocketID != INVALID_SOCKET )
  242.    {
  243.       char character = 0x00;
  244.  
  245.       int number_of_bytes_read = 0;
  246.  
  247.       /*
  248.       ** Need to add CRLF checking!!!!
  249.       */
  250.  
  251.       while( character != LINE_FEED )
  252.       {
  253.          number_of_bytes_read = ::recv( m_SocketID, &character, 1, 0 );
  254.  
  255.          if ( number_of_bytes_read == SOCKET_ERROR )
  256.          {
  257.             TRACE( "CSimpleSocket::Read(), Error in recv() at line %d of %s\n", __LINE__, __FILE__ );
  258.  
  259.             m_ErrorCode = ::WSAGetLastError();
  260.             return;
  261.          }
  262.  
  263.          line_to_read += character;
  264.       }
  265.    }
  266. }
  267.  
  268. void CSimpleSocket::SetAddress( const char *address_string )
  269. {
  270.    /*
  271.    ** Called when a client connects to us. This function also fills in the
  272.    ** client's name for security checking.
  273.    */
  274.  
  275.    ASSERT_VALID( this );
  276.    ASSERT( address_string != NULL );
  277.    ASSERT( AfxIsValidString( address_string ) );
  278.  
  279.    if ( address_string == NULL )
  280.    {
  281.       Address.Empty();
  282.       return;
  283.    }
  284.  
  285.    CString address;
  286.  
  287.    address = address_string;
  288.  
  289.    /*
  290.    ** Address may contain "131.26.31.92" or "cheetah.sed.csc.com"
  291.    ** Given either, we must fill in host_name and IP_address
  292.    */
  293.  
  294.    LPHOSTENT host_entry_p = (LPHOSTENT) NULL;
  295.  
  296.    /*
  297.    ** See if it is in xxx.xxx.xxx.xxx form
  298.    */
  299.  
  300.    int index = 0;
  301.  
  302.    BOOL exit_loop = FALSE;
  303.  
  304.    while( index < address.GetLength() && exit_loop == FALSE )
  305.    {
  306.       if ( address[ index ] != '.' && ! isdigit( address[ index ] ) )
  307.       {
  308.          /*
  309.          ** The character is not a period and not a digit so it cannot meet the requirements
  310.          ** of xxx.xxx.xxx.xxx type address and therefore must be a host name
  311.          */
  312.  
  313.          exit_loop = TRUE;
  314.       }
  315.       else
  316.       {
  317.          index++;
  318.       }
  319.    }
  320.  
  321.    if ( exit_loop == TRUE )
  322.    {
  323.       /*
  324.       ** Tech Note: You must cast the CString object to a const char * when using things like printf()
  325.       */
  326.  
  327.       host_entry_p = ::gethostbyname( (const char *) address );
  328.    }
  329.    else
  330.    {
  331.       ULONG internet_address = 0L;
  332.  
  333.       internet_address = ::inet_addr( address );
  334.       host_entry_p = ::gethostbyaddr( (const char *) &internet_address, 4, PF_INET );
  335.    }
  336.  
  337.    if ( host_entry_p == (LPHOSTENT) NULL )
  338.    {
  339.       TRACE( "CSimpleSocket::set_address(), gethostby???() failed at line %d of %s\n", __LINE__, __FILE__ );
  340.  
  341.       m_ErrorCode = ::WSAGetLastError();
  342.       return;
  343.    }
  344.  
  345.    if ( exit_loop != TRUE )
  346.    {
  347.       Address = address;
  348.    }
  349.    else
  350.    {
  351.       LPSTR dotted_ip_address = (LPSTR) NULL;
  352.  
  353.       /*
  354.       ** You just gotta love the way Unix people thought . . . NOT!
  355.       */
  356.  
  357.       struct in_addr internet_address;
  358.  
  359.       internet_address.S_un.S_un_b.s_b1 = host_entry_p->h_addr_list[ 0 ][ 0 ];
  360.       internet_address.S_un.S_un_b.s_b2 = host_entry_p->h_addr_list[ 0 ][ 1 ];
  361.       internet_address.S_un.S_un_b.s_b3 = host_entry_p->h_addr_list[ 0 ][ 2 ];
  362.       internet_address.S_un.S_un_b.s_b4 = host_entry_p->h_addr_list[ 0 ][ 3 ];
  363.  
  364.       dotted_ip_address = ::inet_ntoa( internet_address );
  365.  
  366.       if ( dotted_ip_address == (LPSTR) NULL )
  367.       {
  368.          return;
  369.       }
  370.  
  371.       Address = dotted_ip_address;
  372.  
  373.       TRACE( "ip_address == \"%s\"\n", (const char *) Address );
  374.    }
  375.  
  376.    /*
  377.    ** We don't call set_name() because that function will call this function and we'll go into an endless loop
  378.    */
  379.  
  380.    Name = host_entry_p->h_name;
  381.  
  382.    /*
  383.    ** Now lets get the aliases for this fella
  384.    */
  385.  
  386.    m_ClearAliasList();
  387.  
  388.    index = 0;
  389.  
  390.    CString *new_string_p = NULL;
  391.  
  392.    while( host_entry_p->h_aliases[ index ] != (char *) NULL )
  393.    {
  394.       new_string_p = new CString( (const char *) host_entry_p->h_aliases[ index ] );
  395.  
  396.       if ( new_string_p != NULL )
  397.       {
  398.          AliasList.AddTail( new_string_p );
  399.       }
  400.  
  401.       index++;
  402.    }
  403. }
  404.  
  405. void CSimpleSocket::SetID( const SOCKET id )
  406. {
  407.    ASSERT_VALID( this );
  408.  
  409.    m_SocketID = id;
  410.    m_hFile    = (UINT) id;
  411. }
  412.  
  413. void CSimpleSocket::SetName( const char *host_string )
  414. {
  415.    ASSERT_VALID( this );
  416.    ASSERT( host_string != NULL );
  417.  
  418.    if ( host_string == NULL )
  419.    {
  420.       Name.Empty();
  421.    }
  422.    else
  423.    {
  424.       Name = host_string;
  425.    }
  426. }
  427.  
  428. void CSimpleSocket::SetPort( const char *name_string )
  429. {
  430.    ASSERT_VALID( this );
  431.    ASSERT( name_string != NULL );
  432.  
  433.    if ( name_string == NULL )
  434.    {
  435.       m_PortName.Empty();
  436.       m_PortNumberInNetworkByteOrder = 0;
  437.       return;
  438.    }
  439.  
  440.    CString name;
  441.  
  442.    name = name_string;
  443.  
  444.    /*
  445.    ** Although not documented anywhere, the name of the protocol must be in lower case
  446.    ** If you look in the data file for getservbyname() [winnt/system32/drivers/etc/services]
  447.    ** you will notice that everything is in lower case. Gotta love Unix . . .
  448.    */
  449.  
  450.    name.MakeLower();
  451.  
  452.    /*
  453.    ** This routine sets port_name and m_PortNumberInNetworkByteOrder
  454.    */
  455.  
  456.    LPSERVENT service_entry_p = (LPSERVENT) NULL;
  457.  
  458.    service_entry_p = ::getservbyname( name, NULL );
  459.  
  460.    if ( service_entry_p == (LPSERVENT) NULL )
  461.    {
  462.       m_ErrorCode = ::WSAGetLastError();
  463.  
  464.       TRACE( "CSimpleSocket::set_server_port(), getservbyname() failed at line %d of %s, Last Error is %d\n", __LINE__, __FILE__, m_ErrorCode );
  465.  
  466.       return;
  467.    }
  468.  
  469.    m_PortName = name;
  470.    m_PortNumberInNetworkByteOrder = service_entry_p->s_port;
  471. }
  472.  
  473. void CSimpleSocket::SetPort( const short p )
  474. {
  475.    ASSERT_VALID( this );
  476.  
  477.    /*
  478.    ** This routine sets port_name and m_PortNumberInNetworkByteOrder
  479.    */
  480.  
  481.    m_PortNumberInNetworkByteOrder = ::htons( p );
  482.  
  483.    /*
  484.    ** Now go find a name for this port . . .
  485.    */
  486.  
  487.    LPSERVENT service_entry_p = (LPSERVENT) NULL;
  488.  
  489.    service_entry_p = ::getservbyport( m_PortNumberInNetworkByteOrder, NULL );
  490.  
  491.    if ( service_entry_p == (LPSERVENT) NULL )
  492.    {
  493.       TRACE( "CSimpleSocket::set_port(), getservbyport() failed at line %d of %s\n", __LINE__, __FILE__ );
  494.  
  495.       m_ErrorCode = ::WSAGetLastError();
  496.       m_PortName.Empty();
  497.       return;
  498.    }
  499.  
  500.    m_PortName = service_entry_p->s_name;
  501. }
  502.  
  503. void __stdcall CSimpleSocket::StartWindowsSockets( void )
  504. {
  505.    /*
  506.    ** Start WINSOCK
  507.    */
  508.  
  509.    WSADATA winsock_data;
  510.  
  511.    int socket_error = 0;
  512.  
  513.    WORD desired_winsock_version = 0x0101; // We'd like WINSOCK v1.1 at least
  514.  
  515.    BYTE major_version_required = 0;
  516.    BYTE minor_version_required = 0;
  517.  
  518.    ::ZeroMemory( &winsock_data, sizeof( winsock_data ) );
  519.  
  520.    socket_error = ::WSAStartup( desired_winsock_version, (LPWSADATA) &winsock_data );
  521.  
  522.    if ( socket_error != 0 )
  523.    {
  524.       TRACE( "WSAStartup failed with an error code of %d at line %d of %s\n", socket_error, __LINE__, __FILE__ );
  525.       AfxAbort();
  526.    }
  527.  
  528.    major_version_required = HIBYTE( desired_winsock_version );
  529.    minor_version_required = LOBYTE( desired_winsock_version );
  530.  
  531.    if ( (   LOBYTE( winsock_data.wVersion ) <  major_version_required ) ||
  532.         (   LOBYTE( winsock_data.wVersion ) == major_version_required ) &&
  533.         ( ( HIBYTE( winsock_data.wVersion ) <  minor_version_required ) ) )
  534.    {
  535.       TRACE( "Need a later version of Winsock\n" );
  536.    }
  537. }
  538.  
  539. void __stdcall CSimpleSocket::StopWindowsSockets( void )
  540. {
  541.    ::WSACleanup();
  542. }
  543.  
  544. void __stdcall CSimpleSocket::TranslateErrorCode( DWORD error_code, LPSTR destination_string, DWORD size_of_destination_string )
  545. {
  546.    switch( error_code )
  547.    {
  548.       /*
  549.       ** Following are Windows Sockets Library errors
  550.       */
  551.  
  552.       case WSAENOTSOCK:
  553.  
  554.         strncpy( destination_string, "WSAENOTSOCK, Socket operation on non-socket. A socket created in one process is used by another process.", size_of_destination_string );
  555.         return;
  556.  
  557.       case WSAEDESTADDRREQ:
  558.  
  559.         strncpy( destination_string, "WSAEDESTADDRREQ, Destination address required", size_of_destination_string );
  560.         return;
  561.  
  562.       case WSAEMSGSIZE:
  563.  
  564.         strncpy( destination_string, "WSAEMSGSIZE, Message too long", size_of_destination_string );
  565.         return;
  566.  
  567.       case WSAEPROTOTYPE:
  568.  
  569.         strncpy( destination_string, "WSAEPROTOTYPE, Protocol wrong type for socket", size_of_destination_string );
  570.         return;
  571.  
  572.       case WSAENOPROTOOPT:
  573.  
  574.         strncpy( destination_string, "WSAENOPROTOOPT, Protocol not available", size_of_destination_string );
  575.         return;
  576.  
  577.       case WSAEPROTONOSUPPORT:
  578.  
  579.         strncpy( destination_string, "WSAEPROTONOSUPPORT, Protocol not supported", size_of_destination_string );
  580.         return;
  581.  
  582.       case WSAESOCKTNOSUPPORT:
  583.  
  584.         strncpy( destination_string, "WSAESOCKTNOSUPPORT, Socket type not supported", size_of_destination_string );
  585.         return;
  586.  
  587.       case WSAEOPNOTSUPP:
  588.  
  589.         strncpy( destination_string, "WSAEOPNOTSUPP, Operation not supported on socket", size_of_destination_string );
  590.         return;
  591.  
  592.       case WSAEPFNOSUPPORT:
  593.  
  594.         strncpy( destination_string, "WSAEPFNOSUPPORT, Protocol family not supported", size_of_destination_string );
  595.         return;
  596.  
  597.       case WSAEAFNOSUPPORT:
  598.  
  599.         strncpy( destination_string, "WSEAFNOSUPPORT, Address family not supported by protocol family", size_of_destination_string );
  600.         return;
  601.  
  602.       case WSAEADDRINUSE:
  603.  
  604.         strncpy( destination_string, "WSAEADDRINUSE, Triggered by bind() because a process went down without closing a socket.", size_of_destination_string );
  605.         return;
  606.  
  607.       case WSAEADDRNOTAVAIL:
  608.  
  609.         strncpy( destination_string, "WSAEADDRNOTAVAIL, Can't assign requested address", size_of_destination_string );
  610.         return;
  611.  
  612.       case WSAENETDOWN:
  613.  
  614.         strncpy( destination_string, "WSAENETDOWN, Network is down", size_of_destination_string );
  615.         return;
  616.  
  617.       case WSAENETUNREACH:
  618.  
  619.         strncpy( destination_string, "WSAENETUNREACH, Network is unreachable", size_of_destination_string );
  620.         return;
  621.  
  622.       case WSAENETRESET:
  623.  
  624.         strncpy( destination_string, "WSAENETRESET, Network dropped connection or reset", size_of_destination_string );
  625.         return;
  626.  
  627.       case WSAECONNABORTED:
  628.  
  629.         strncpy( destination_string, "WSAECONNABORTED, Software caused connection abort", size_of_destination_string );
  630.         return;
  631.  
  632.       case WSAECONNRESET:
  633.  
  634.         strncpy( destination_string, "WSAECONNRESET, Connection reset by peer", size_of_destination_string );
  635.         return;
  636.  
  637.       case WSAENOBUFS:
  638.  
  639.         strncpy( destination_string, "WSAENOBUFS, No buffer space available.", size_of_destination_string );
  640.         return;
  641.  
  642.       case WSAEISCONN:
  643.  
  644.         strncpy( destination_string, "WSAEISCONN, Socket is already connected", size_of_destination_string );
  645.         return;
  646.  
  647.       case WSAENOTCONN:
  648.  
  649.         strncpy( destination_string, "WSAENOTCONN, Socket is not connected", size_of_destination_string );
  650.         return;
  651.  
  652.       case WSAESHUTDOWN:
  653.  
  654.         strncpy( destination_string, "WSAESHUTDOWN, Can't send after socket shutdown", size_of_destination_string );
  655.         return;
  656.  
  657.       case WSAETIMEDOUT:
  658.  
  659.         strncpy( destination_string, "WSAETIMEDOUT, Connection timed out", size_of_destination_string );
  660.         return;
  661.  
  662.       case WSAECONNREFUSED:
  663.  
  664.         strncpy( destination_string, "WSAECONNREFUSED, Connection refused", size_of_destination_string );
  665.         return;
  666.  
  667.       case WSAEHOSTDOWN:
  668.  
  669.         strncpy( destination_string, "WSAEHOSTDOWN, Networking subsystem not started", size_of_destination_string );
  670.         return;
  671.  
  672.       case WSAEHOSTUNREACH:
  673.  
  674.         strncpy( destination_string, "WSAEHOSTUNREACH, No route to host", size_of_destination_string );
  675.         return;
  676.  
  677.       case WSAEWOULDBLOCK:
  678.  
  679.         strncpy( destination_string, "WSAEWOULDBLOCK, Operation would block", size_of_destination_string );
  680.         return;
  681.  
  682.       case WSAEINPROGRESS:
  683.  
  684.         strncpy( destination_string, "WSAEINPROGRESS, Operation now in progress", size_of_destination_string );
  685.         return;
  686.  
  687.       case WSAEALREADY:
  688.  
  689.         strncpy( destination_string, "WSAEALREADY, Operation already in progress", size_of_destination_string );
  690.         return;
  691.  
  692.       case WSAEINTR:
  693.  
  694.         strncpy( destination_string, "WSAEALREADY, Operation was interrupted", size_of_destination_string );
  695.         return;
  696.  
  697.       case WSAEBADF:
  698.  
  699.         strncpy( destination_string, "WSAEBADF, Bad file number", size_of_destination_string );
  700.         return;
  701.  
  702.       case WSAEACCES:
  703.  
  704.         strncpy( destination_string, "WSAEACCES, Access is denied", size_of_destination_string );
  705.         return;
  706.  
  707.       case WSAEFAULT:
  708.  
  709.         strncpy( destination_string, "WSAEFAULT, Bad memory address", size_of_destination_string );
  710.         return;
  711.  
  712.       case WSAEINVAL:
  713.  
  714.         strncpy( destination_string, "WSAEINVAL, The socket has not been bound with bind() or is already connected", size_of_destination_string );
  715.         return;
  716.  
  717.       case WSAEMFILE:
  718.  
  719.         strncpy( destination_string, "WSAEMFILE, No more file descriptors are available", size_of_destination_string );
  720.         return;
  721.  
  722.       case WSAETOOMANYREFS:
  723.  
  724.         strncpy( destination_string, "WSAETOOMANYREFS, Undocumented WinSock error", size_of_destination_string );
  725.         return;
  726.  
  727.       case WSAENAMETOOLONG:
  728.  
  729.         strncpy( destination_string, "WSAENAMETOOLONG, Undocumented WinSock error", size_of_destination_string );
  730.         return;
  731.  
  732.       case WSAENOTEMPTY:
  733.  
  734.         strncpy( destination_string, "WSAENOTEMPTY, Undocumented WinSock error", size_of_destination_string );
  735.         return;
  736.  
  737.       case WSAEPROCLIM:
  738.  
  739.         strncpy( destination_string, "WSAEPROCLIM, Undocumented WinSock error", size_of_destination_string );
  740.         return;
  741.  
  742.       case WSAEUSERS:
  743.  
  744.         strncpy( destination_string, "WSAEUSERS, Undocumented WinSock error", size_of_destination_string );
  745.         return;
  746.  
  747.       case WSAEDQUOT:
  748.  
  749.         strncpy( destination_string, "WSAEDQUOT, Undocumented WinSock error", size_of_destination_string );
  750.         return;
  751.  
  752.       case WSAESTALE:
  753.  
  754.         strncpy( destination_string, "WSAESTALE, Undocumented WinSock error", size_of_destination_string );
  755.         return;
  756.  
  757.       case WSAEREMOTE:
  758.  
  759.         strncpy( destination_string, "WSAEREMOTE, Undocumented WinSock error", size_of_destination_string );
  760.         return;
  761.  
  762.       case WSAEDISCON:
  763.  
  764.         strncpy( destination_string, "WSAEDISCON, Circuit was gracefully terminated", size_of_destination_string );
  765.         return;
  766.  
  767.       case WSASYSNOTREADY:
  768.  
  769.         strncpy( destination_string, "WSASYSNOTREADY, The underlying network subsystem is not ready for network communication", size_of_destination_string );
  770.         return;
  771.  
  772.       case WSAVERNOTSUPPORTED:
  773.  
  774.         strncpy( destination_string, "WSAVERNOTSUPPORTED, The version of Windows Sockets API support requested is not provided by this particular Windows Sockets implementation", size_of_destination_string );
  775.         return;
  776.  
  777.       case WSANOTINITIALISED:
  778.  
  779.         strncpy( destination_string, "WSANOTINITIALISED, WSAStartup() has not been called", size_of_destination_string );
  780.         return;
  781.  
  782.       case WSAHOST_NOT_FOUND:
  783.  
  784.         strncpy( destination_string, "WSAHOST_NOT_FOUND, Authoritative answer host not found", size_of_destination_string );
  785.         return;
  786.  
  787.       case WSATRY_AGAIN:
  788.  
  789.         strncpy( destination_string, "WSATRY_AGAIN, Non-authoritative answer host not found or SERVERFAIL", size_of_destination_string );
  790.         return;
  791.  
  792.       case WSANO_RECOVERY:
  793.  
  794.         strncpy( destination_string, "WSANO_RECOVERY, Non recoverable errors, FORMERR, REFUSED, NOTIMP", size_of_destination_string );
  795.         return;
  796.  
  797.       case WSANO_DATA:
  798.  
  799.         strncpy( destination_string, "WSANO_DATA or WSANO_ADDRESS, Valid name, no data record of requested type", size_of_destination_string );
  800.         return;
  801.  
  802.       default:
  803.  
  804.          {
  805.             TCHAR message_string[ 129 ];
  806.  
  807.             wsprintf( (LPTSTR) message_string, (LPCSTR) TEXT( "Unknown WinSock Error Number %d" ), error_code );
  808.             strncpy( destination_string, message_string, size_of_destination_string );
  809.          }
  810.  
  811.          return;
  812.    }
  813. }
  814.  
  815. void CSimpleSocket::Write( const VOID *buffer, const long number_of_bytes_to_write )
  816. {
  817.    ASSERT_VALID( this );
  818.    ASSERT( buffer != NULL );
  819.    ASSERT( number_of_bytes_to_write > 0L );
  820.  
  821.    if ( buffer == NULL )
  822.    {
  823.       return;
  824.    }
  825.  
  826.    if ( m_SocketID == INVALID_SOCKET )
  827.    {
  828.       return;
  829.    }
  830.  
  831.    BYTE *byte_buffer = (BYTE *) NULL;
  832.  
  833.    byte_buffer = (BYTE *) buffer;
  834.  
  835.    if ( byte_buffer == (BYTE *) NULL )
  836.    {
  837.       return;
  838.    }
  839.  
  840.    /*
  841.    ** Loop until the bytes are sent or until we give up
  842.    */
  843.  
  844.    BOOL bytes_were_sent = FALSE;
  845.  
  846.    int number_of_bytes_sent = 0;
  847.    int loop_count           = 0;
  848.  
  849.    while( bytes_were_sent == FALSE && loop_count < 100 )
  850.    {
  851.       number_of_bytes_sent = ::send( m_SocketID, (const char *) byte_buffer, number_of_bytes_to_write, 0 );
  852.  
  853.       if ( number_of_bytes_sent == SOCKET_ERROR )
  854.       {
  855.          m_ErrorCode = ::WSAGetLastError();
  856.  
  857.          char temp_string[ 513 ];
  858.  
  859.          TranslateErrorCode( m_ErrorCode, temp_string, sizeof( temp_string ) );
  860.  
  861.          TRACE1( "CSimpleSocket::Write, %s\n", temp_string );
  862.  
  863.          if ( m_ErrorCode != WSAENOBUFS &&
  864.               m_ErrorCode != WSAEINPROGRESS )
  865.          {
  866.             if ( m_ErrorCode == WSAENOTCONN  ||
  867.                  m_ErrorCode == WSAENETRESET ||
  868.                  m_ErrorCode == WSAESHUTDOWN )
  869.             {
  870.                /*
  871.                ** Someone hung up on us or unplugged our lan cable
  872.                */
  873.  
  874.                m_SocketID = INVALID_SOCKET;
  875.                m_hFile    = CFile::hFileNull;
  876.             }
  877.  
  878.             return;
  879.          }
  880.          else
  881.          {
  882.             loop_count++;
  883.          }
  884.       }
  885.       else
  886.       {
  887.          bytes_were_sent = TRUE;
  888.       }
  889.    }
  890. }
  891.  
  892. void CSimpleSocket::Write( const CString& string_to_write )
  893. {
  894.    ASSERT_VALID( this );
  895.  
  896.    CString temp_string;
  897.  
  898.    temp_string = string_to_write;
  899.  
  900.    Write( (VOID *) temp_string.GetBuffer( temp_string.GetLength() + 1 ), temp_string.GetLength() );
  901. }
  902.  
  903. #pragma warning( default : 4100 )
  904.